﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Reflection;

namespace TemplateEngine
{
    public class Engine
    {
        private const string cBracketRegEx = @"\[(?<Tag>.+?)\]";

        private Object m_sourceObject;

        public string Process(string inputText, Object sourceObject)
        {
            Regex _Regex = new Regex(cBracketRegEx);
            m_sourceObject = sourceObject;
            return _Regex.Replace(inputText, new MatchEvaluator(Replace));
        }

        private string Replace(Match match)
        {
            try
            {

                string lookupTag = match.Groups["Tag"].Value;
                string[] tree = lookupTag.Split('.');

                Object sourceObj = m_sourceObject;

                for (int i = 0; i < tree.Length; i++)
                {
                    if (i == tree.Length - 1)
                    { // last
                        Type _type = sourceObj.GetType();
                        FieldInfo[] _Fields = _type.GetFields();
                        foreach (FieldInfo _Field in _Fields)
                        {
                            if (_Field.Name.Equals(tree[i]))
                            {
                                return string.Format("{0}", _Field.GetValue(sourceObj));
                            }
                        }
                        PropertyInfo[] _Properties = _type.GetProperties();
                        foreach (PropertyInfo _Prop in _Properties)
                        {
                            if (_Prop.Name.Equals(tree[i]))
                            {
                                try
                                {
                                    return String.Format("{0}", _Prop.GetValue(sourceObj, null));
                                }
                                catch (Exception E)
                                {
                                    return String.Format("[Excep: {0}]", E.ToString());
                                }
                            }
                        }
                    }
                    else
                    {
                        Type _type = sourceObj.GetType();
                        FieldInfo[] _Fields = _type.GetFields();
                        foreach (FieldInfo _Field in _Fields)
                        {
                            if (_Field.Name.Equals(tree[i]))
                            {
                                sourceObj = _Field.GetValue(sourceObj);
                                break;
                            }
                        }

                        PropertyInfo[] _Properties = _type.GetProperties();
                        foreach (PropertyInfo _Prop in _Properties)
                        {
                            if (_Prop.Name.Equals(tree[i]))
                            {
                                sourceObj = _Prop.GetValue(sourceObj, null);
                                break;
                            }
                        }
                    }
                }

                return match.Value;
            }
            catch (Exception E)
            {
                return String.Format("[Excep: {0}]", E.ToString());
            }

        }

        public string ProcessFile(string location, Object sourceObject)
        {
            if (!File.Exists(location))
                throw new FileNotFoundException();

            TextReader _TR = File.OpenText(location);
            string inputText = _TR.ReadToEnd();
            _TR.Close();

            return Process(inputText, sourceObject);
        }
    }
}
